<?php
    define('PIXEL_MODE', 'cli');
    require dirname(dirname(__FILE__)).'/config/environment.php';
    $g= new Generator();
    $g->run();

    class Generator {

        var $view_path, $controller_path, $helper_path, $model_path, $extra_path, $controller_name, $model_name;
        var $controller_template_file, $helper_template_file, $view_template_file, $model_template_file; 
        var $model_test_template_file, $controller_scaffold_file, $index_scaffold_file;
        var $model_scaffold_file, $view_scaffold_file, $modify_scaffold_file;
        var $view_file_extention = "php";

        function Generator() {
            $this->view_path                = VIEWS;
            $this->controller_path          = CONTROLLERS;
            $this->helper_path              = HELPERS;
            $this->model_path               = MODELS;
            $this->test_path                = TESTS;
            
            // templates
            $tpl_dir                        = VENDOR . "/pixel/templates/";
            $this->controller_template_file = $tpl_dir."controller.php";
            $this->helper_template_file     = $tpl_dir."helper.php";
            $this->view_template_file       = $tpl_dir."view.php";
            $this->model_template_file      = $tpl_dir."model.php";
            $this->model_test_template_file = $tpl_dir."model_test.php";
            $this->controller_scaffold_file = $tpl_dir."controller_scaffold.php";
            $this->index_scaffold_file      = $tpl_dir."index_scaffold.php";
            $this->model_scaffold_file      = $tpl_dir."model_scaffold.php";
            $this->view_scaffold_file       = $tpl_dir."view_scaffold.php";
            $this->modify_scaffold_file     = $tpl_dir."modify_scaffold.php";
        }

        function run() 
        {        
            $command      = strtolower($_SERVER["argv"][1]); 
            $command_name = $_SERVER["argv"][2];

            if( empty($command) ) {            
                $this->generator_help();           
            } else {            
                switch( $command ) {
                    case "controller":
                        if( empty($command_name) ) {
                            $this->controller_help();                             
                        } else {
                            if( $_SERVER["argv"][3] != "" ) {
                                for($i=3;$i < count($_SERVER["argv"]);$i++) {
                                    $views[] = strtolower($_SERVER["argv"][$i]);           
                                }
                            }                      
                            $this->generate_controller($command_name,$views);                                 
                        }
                        break;
                    case "model":   
                        if( empty($command_name) ) {
                            $this->model_help();                             
                        } else {                
                            $this->generate_model($command_name);
                        }
                        break; 
                   case 'scaffold':
                        if ( empty($command_name) )
                        {
                            $this->scaffold_help();
                        } else {
                            if ( !empty($_SERVER['argv'][2]) && !empty($_SERVER['argv'][3]) )
                            {
                                $this->generate_scaffolding($_SERVER['argv'][2],$_SERVER['argv'][3]);
                            } else {
                                $this->scaffold_help();
                            }                            
                        }
                        break;
                   default:
                      echo "The available commands are controller, model or scaffold\n";
                   break;  
                }               
            }        
            exit;
        }
        
        function generate_scaffolding($controller,$model)
        {
            $this->set_up_controller($controller);
            if ( $this->generate_model($model,true) ) {
                $this->generate_controller($controller,null,true);
            }
        }
        
        function generate_scaffold_views()
        {
            // index view
            $this->create_view('index',
                                $this->controller_name,
                                file_get_contents($this->index_scaffold_file));
            // view view lol.
            $view_code = file_get_contents($this->view_scaffold_file);
            $view_code = str_replace('[controller_name]',$this->controller_url,$view_code);
            $this->create_view('view',
                               $this->controller_name,
                               $view_code);
            
            // modify view
            $modify_code = file_get_contents($this->modify_scaffold_file);
            $modify_code = str_replace('[model_name]',$this->model_name,$modify_code);
            $this->create_view('modify',
                               $this->controller_name,
                               $modify_code);
            // form
            $form_code = $this->get_model_form_code();
            $this->create_view('_form',
                               $this->controller_name,
                               $form_code);
        }

        function get_model_form_code()
        {
            if ( empty($this->model_name) )
            {
                trigger_error('Model not yet created, can not create model form code',FATAL);
                return;
            }
            $form_code = ' ';
            // connnect to db and get the field attributes to create appropriate form fields
            $db = ActiveRecord::connect();
            $columns = $db->MetaColumns($this->model_name,false); 
            foreach( $columns as $column) 
            {	
                $field_html = '';		                
                switch ( $column->type) {
                    case 'float':
                    case 'double':
                    case 'integer':
                    case 'tinyint':
                    case 'smallint':
                    case 'int':
                    case 'bigint':
                    case 'char':
                    case 'varchar':
                    case 'tinytext':
                    case 'tinyblob':
                        $field_html = "text_field('{$this->model_name}','{$column->name}',".
                                      "array('maxlength'=>'{$column->max_length}'))";
                        break;
                    case 'text':
                    case 'mediumtext':
                    case 'longtext':
                    case 'blob':
                    case 'mediumblob':
                    case 'longblob':
                        $field_html = "text_area('{$this->model_name}','{$column->name}',".
                                      "array('size'=>'30x5'))";       
                        break;                
                    case 'enum':
                        $field_html = "select_tag('{$this->model_name[$column->name]}','".
                                      options_for_select($column->enums)."')";
                        break;
                    case 'date':
                        $field_html = "date_select('{$this->model_name}','{$column->name}')";
                        break;
                    case 'time':
                            $field_html = "time_select('{$this->model_name}','{$column->name}')";
                        break;
                    case 'datetime':
                    case 'timestamp':
                        $field_html = "datetime_select('{$this->model_name}','{$column->name}')";
                        break;
                    case 'year':
                        $field_html = "select_year(null,array('field_name'=>'{$this->model_name[$column->name]}'))";
                        break;
                    default:
                        $field_html = "text_field('{$this->model_name}','{$column->name}')";
                        break;                        
                }
                if ( strncasecmp($column->name,'id',2) == 0 )
                {
                    $form_code .= "<?php echo hidden_field('{$this->model_name}','{$column->name}')?>";
                } else {
                    $form_code .= content_tag('p', $this->humanize($column->name).'<br /><?php echo '.$field_html.'?>')."\n" ;
                }
            }
            return $form_code;
        }
        
        function set_up_controller($name)
        {
            if ($this->controller_setup) return;
            // set extra paths if they are given, like admin/sample
            if(stristr($name, "/")) {                
                $path    = explode('/',$name);
                $cname   = array_pop($path);
                $newpath = '/'.strtolower(implode('/',$path));                
                $this->controller_name = $this->underscore(strtolower($cname));
                
                // now make directories for the controller, views, helpers
                $this->controller_path .= $newpath;                
                $this->view_path       .= $newpath.'/'.$this->controller_name;
                $this->helper_path     .= $newpath;                                
                
            } else {
                $this->controller_name = $this->underscore($name);
                $this->view_path .= "/{$this->controller_name}";
            }
            $this->controller_url = $name;
            $this->controller_setup = true;
        }
        
        function generate_controller($name, $views, $scaffold=false) 
        {   
            $this->set_up_controller($name);
                         
            if (empty($views)) $views = array('index');

            $camel_cased_word  = $this->camelize($this->controller_name);
            $camel_cased_word = preg_replace('/([A-Z]+)([A-Z])/','\1_\2',$camel_cased_word);
            $this->controller_class = preg_replace('/([a-z])([A-Z])/','\1_\2',$camel_cased_word); 

            // Create the extra folders for View / Controller  
            mkdirs($this->view_path) ;
            mkdirs($this->controller_path) ;
            mkdirs($this->helper_path) ;      

            // Create the actual controller/helper files
            $this->create_controller($this->controller_name,$views,$scaffold);
            $this->create_helper($this->controller_name);                                     
            
            if ( $scaffold )
            {
                $this->generate_scaffold_views();
            } else {
                // Create view files if any
                foreach($views as $view) {
                   $this->create_view($view,$this->controller_name);       
                }
            }                 
        }

        function generate_model($name,$scaffold=false) 
        {
        
            // verify that the db and table exist
            $db = ActiveRecord::connect();
            $sql = $db->Execute("SHOW COLUMNS FROM $name");            
            if ( $sql === false ) {
                echo "Table does not exist to create model file.";
                return false;
            }
            $this->model_name  = $this->underscore($name);
            $model_file        = $this->model_path.'/' .$this->model_name.".php"; 
            $camel_cased_word  = $this->camelize($name);
            $camel_cased_word  = preg_replace('/([A-Z]+)([A-Z])/','\1_\2',$camel_cased_word);
            $model_class       = preg_replace('/([a-z])([A-Z])/','\1_\2',$camel_cased_word);      

            if(!file_exists($model_file)) {            
                if(file_exists($this->model_template_file)) {
                    $template = file_get_contents($this->model_template_file);
                    $template = str_replace('[class_name]',$model_class,$template);
                    $template = str_replace('[table_name]',strtolower($model_class),$template); 
                    
                    // scaffolding
                    if ( $scaffold )
                    {
                        $scaffold_code = file_get_contents($this->model_scaffold_file);
                        $scaffold_code = str_replace('[controller_path]',
                                                     $this->controller_url,
                                                     $scaffold_code);
                        $template = str_replace('[scaffold]',$scaffold_code,$template);
                    } else {
                        $template = str_replace('[scaffold]','',$template);
                    }
                                      
                    if( $fp = fopen($model_file,"w+") )
                    {
                       if ( fwrite($fp,$template) !== false ) 
                       {
                           echo "created $model_file\n";
                       } else {
                           echo "error writing model file: $model_file\n";       
                           exit;
                       }
                    } else {
                        echo "error creating model file: $model_file\n";    
                        exit;   
                    }

                } else {
                    echo "error model template file doesn't exist: $this->model_template_file\n";    
                }
            } else {
                echo "exists $model_file\n";        
            }
            
            // write stub test
            $model_test_file = $this->test_path.'/model_'.$this->underscore($name).'_test.php';
            if ( !file_exists($model_test_file) ) {
                if(file_exists($this->model_test_template_file)) {
                    $template = file_get_contents($this->model_test_template_file);
                    $template = str_replace('[class_name]',$model_class,$template);                    
                    if( $fp = fopen($model_test_file,"w+") )
                    {
                       if ( fwrite($fp,$template) !== false ) 
                       {
                           echo "created test stub for: $model_test_file\n";
                       } else {
                           echo "error writing model file: $model_test_file\n";       
                           exit;
                       }
                    } else {
                        echo "error creating model file: $model_test_file\n";    
                        exit;   
                    }

                } else {
                    echo "error: model test template file doesn't exist: $this->model_test_template_file\n";    
                }
            } else {
                echo "error: test file already exists\n";
            } 
            return true;             
        }

        function create_controller($controller,$views,$scaffold=false) 
        {        
            $controller_file = $this->controller_path.'/'.$controller."_controller.php";

            if(!file_exists($controller_file)) {            

                if(file_exists($this->controller_template_file)) {
                    $template = file_get_contents($this->controller_template_file);
                    $template = str_replace('[class_name]',$this->controller_class,$template);
                    
                    if ( $scaffold )
                    {
                        $actions = array("'index'","'view'","'modify'","'delete'");
                        $template = str_replace('[actions]',implode(",",$actions),$template);
                        $controller_scaffold_code = file_get_contents($this->controller_scaffold_file);
                        $controller_scaffold_code = str_replace('[model_name]',$this->model_name,$controller_scaffold_code);
                        $template = str_replace('[class_methods]',$controller_scaffold_code,$template);
                        $template = str_replace('[use_model]','use_model(\''.$this->model_name.'\');',$template);
                    } else {
                        if(is_array($views)) {
                            foreach($views as $view) {
                                $classMethods[] = "\t\tfunction {$view}() \n\t\t{\n\t\t}\n";
                                $actions[] = "'{$view}'";                
                            }
                            $actions    = implode(",",$actions) ;
                            $classMethods = implode("\n\n",$classMethods);                 
                        } 
                        $template = str_replace('[actions]',$actions,$template);
                        $template = str_replace('[class_methods]',$classMethods,$template);
                        $template = str_replace('[use_model]','',$template);
                    }
                    if ( $fp = fopen($controller_file,"w+") )
                    {
                      if ( fwrite($fp,$template) !== false )
                      {
                         echo "created $controller_file\n";                      
                      } else {
                         echo "error writing to file: $controller_file\n";
                         exit;
                      }
                    } else {                
                        echo "error creating controller class file: $controller_file\n";  
                        exit;
                    }

                } else {
                    echo "error controller template file doesn't exist: $this->controller_template_file\n";    
                }
            } else {
                echo "exists $controller_file\n";        
            }        
        }

        function create_helper($controller) 
        {        
            $helper_file = $this->helper_path.'/'.$controller."_helper.php";

            if(!file_exists($helper_file)) {            

                if(file_exists($this->helper_template_file)) {
                    $template = file_get_contents($this->helper_template_file);
                    $template = str_replace('[class_name]',$this->controller_class,$template);

                    if ( $fp = fopen($helper_file,"w+") )
                    {
                       if ( fwrite($fp,$template) !== false ) 
                       {
                           echo "created $helper_file\n";     
                       } else {
                           echo "error writing helper file: $helper_file\n";
                           exit;   
                       }
                    } else {                
                       echo "error creating helper file: $helper_file\n";
                       exit;
                    }                               

                } else {
                    echo "error helper template file doesn't exist: $this->helper_template_file\n";    
                }

            } else {
                echo "exists $helper_file\n";        
            }        
        }    

        function create_view($view,$controller,$content=false) 
        {
            $view_file = $this->view_path.'/'.$view.".".$this->view_file_extention;
            if(!file_exists($view_file)) {            
                if(file_exists($this->view_template_file)) {
                    if ( $content )
                    {
                        $template = $content;
                    } else {
                        $xtra = !empty($this->extra_path) ? "{$this->extra_path}/" : '';
                        $template = file_get_contents($this->view_template_file);
                        $template = str_replace('[class_name]',$this->controller_class,$template);
                        $template = str_replace('[controller]',$xtra.$controller,$template);
                        $template = str_replace('[view]',$view,$template);                
                    }
                    if ( $fp = fopen($view_file,"w+") )
                     {
                        if ( fwrite($fp,$template) !== false )
                        {
                           echo "created $view_file\n";    
                        } else {
                           echo "error writing to file: $view_file\n";
                           exit;
                        }
                     } else {                
                         echo "error creating view file: $view_file\n";  
                         exit;
                     }
                } else {
                    echo "error view template file doesn't exist: $this->view_template_file\n";    
                }
            } else {
                echo "exists $view_file\n";        
            }        
        }
        
        function camelize($lower_case_and_underscored_word)
        {
            return str_replace(" ","",ucwords(str_replace("_"," ",$lower_case_and_underscored_word)));
        }    

        function underscore($camel_cased_word) 
        {
            $camel_cased_word = preg_replace('/([A-Z]+)([A-Z])/','\1_\2',$camel_cased_word);
            return strtolower(preg_replace('/([a-z])([A-Z])/','\1_\2',$camel_cased_word));
        }

        function humanize($word)
        {
            return ucwords(str_replace('_',' ',$word));
        }
        
        function controller_help() 
        {
            echo "Usage: generator.php controller ControllerName [view1 view2 ...]\n\n";                                                                                                                                                                                                 
            echo "Description:\n";                                                                  
            echo "\tThe controller generator creates functions for a new controller and its views.\n\n";                                                                            
            echo "\tThe generator takes a controller name and a list of views as arguments.\n";   
            echo "\tThe controller name may be given in CamelCase or under_score and should\n";   
            echo "\tnot be suffixed with 'Controller'.";                                                                               
            echo "\tThe generator creates a controller class in app/controllers with view\n";   
            echo "\ttemplates in app/views/controller_name.\n\n";                                                                                                     
            echo "Example:\n";                                                                 
            echo "\t./script/generate.php controller CreditCard open debit credit close\n\n";                                                                                    
            echo "\tCredit card controller with URLs like /credit_card/debit.\n";                
            echo "\t\tController: app/controllers/credit_card_controller.php\n";                 
            echo "\t\tViews:      app/views/credit_card/debit.tpl.php [...]\n\n";                                                                                            
        }

        function model_help() 
        {
            echo "Usage: generator.php model ModelName [table1 table2 ...]\n";                                                                                                                   
            echo "Description:\n";                                                                  
            echo "\tThe model generator creates functions for a new model.\n";                                                                                                    
            echo "\tThe generator takes a model name and list of tables as its argument.\n";
            echo "\tThe model name may be given in CamelCase or under_score \n";
            echo "\tand should not be suffixed with 'Model'.\n";                                                                           
            echo "\tThe generator creates a model class in app/models.\n";                                                                                              
            echo "Example:\n";                                                                      
            echo "\t./script/generate.php model Account\n";                                                                                                                       
            echo "\tThis will create an Account model:\n";                                       
            echo "\t\tModel:      app/models/account.php\n\n";        
        }
        
        function scaffold_help()
        {
            echo "Usage: generator.php scaffold ControllerName TableName\n"; 
        }

        function generator_help() 
        {   
            echo "Usage:\n";
            echo "Generate Controller:\n";
            echo "generator.php controller controller_name [view1 view2 ..]\n"; 
            echo "for more controller info generator.php controller\n";
            echo "Generate Model:\n";
            echo "generator.php model model_name [table1 table2 ...] \n";
            echo "for more model info generator.php model\n\n";         
        }
    }


?>